/**
*********************************************************************************************************
*               Copyright(c) 2018, Realtek Semiconductor Corporation. All rights reserved.
**********************************************************************************************************
* @file     uartTrans_task.c
* @brief    This module realize HCI event and ack message processing which received from BBPro.
* @details
* @author
* @date     2019-01-11
* @version  v1.0
*********************************************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
///#define LOG_TAG    "8763T"
#include "asr_rtl8763bo_port.h"

#if USE_LV_BLUETOOTH != 0

#include "rtl8763bf_task.h"
#include "bt_api.h"
#include "hci_cmd.h"


/* Defines -------------------------------------------------------------------*/

#define BBPRO_HCI_SEND_TASK_PRIORITY                30 ///70
#define BBPRO_HCI_SEND_TASK_STACK_SIZE              8192
#define BBPRO_HCI_SEND_TASK_MSGQ_SIZE               0x30

#define BBPRO_HCI_RECEIVE_TASK_PRIORITY             30 ///70
#define BBPRO_HCI_RECEIVE_TASK_STACK_SIZE           8192
#define BBPRO_HCI_RECEIVE_TASK_MSGQ_SIZE            0x30

#define BBPRO_HCI_ACK_MSGQ_SIZE                     0x10

#define BBPRO_MAX_RESEND_COUNT                      4
#define BBPRO_CMD_RECHECK_INTERVAL                  5000

#define BBPRO_PCM_TX_TRIGGER_TIMEOUT                (5)  /// 5ms
#define EVENT_REQ_SBC_FRAME_TIMEOUT                 (10*1000)  /// 10s
uint8_t bbpro_peer_bd_addr[6];

extern int8_t bbpro_play_state;

/* Globals ------------------------------------------------------------------ */


#ifndef INVALID_MSGQ_ID
#define INVALID_MSGQ_ID    64
#endif

#ifndef INVALID_TIMER_ID
#define INVALID_TIMER_ID    64
#endif


TASK_HANDLE * bbpro_hci_send_task_handle = NULL;
TASK_HANDLE * bbpro_hci_receive_task_handle = NULL;

uint8_t bbppro_hci_ack_queue_handle = INVALID_MSGQ_ID;
uint8_t g_uart_rx_mutex_lock = INVALID_MUTEX_ID;
uint8_t sbcframe_request_flag = INVALID_FLAG_ID;

#ifdef DEBUG_SBC_FRAME_TIMEOUT_RAW_DATA
static void * g_EVENT_REQ_SBC_FRAME_Timer = NULL;
#endif
static void * g_bbpro_PCMTxTimer = NULL;

rbuf_t * g_pcm_tx_rbuf = NULL;
rbuf_t * g_pcm_rx_rbuf = NULL;

uint8_t bbpro_peer_bd_addr[6];
bool WaitingHCIAckFlag = false;

extern int bbpro_request_sbc_play(void);
extern int bbpro_request_sbc_pause(void);
extern int bbpro_request_sbc_stop(void);
extern int bbpro_request_sbc_prev(void);
extern int bbpro_request_sbc_next(void);

extern HCI_TransInfoTypeDef hci_trans_info;

void uart_rx_lock(void)
{
    ///uos_take_mutex(g_uart_rx_mutex_lock);
}

void uart_rx_unlock(void)
{
    ///uos_release_mutex(g_uart_rx_mutex_lock);
}

void EVENT_REQ_SBC_FRAME_timeout(UINT32 arg)
{
#ifdef DEBUG_SBC_FRAME_TIMEOUT_RAW_DATA
    T_HCI_MSG msg;

    bt_uart_mask_RxInt(1, 0);
    bt_uart_enable(1, 0);

    msg.type = HCI_MSG_TYPE_8763BF;
    msg.subtype = BBPRO_HCI_EVENT_REQ_SBC_FRAME_TIMEOUT;
    msg.u.buf = (void *)arg;
    bbpro_hci_msg_queue_send(&msg);
#endif
}

void EVENT_REQ_SBC_FRAME_start_timer(void * param)
{
#ifdef DEBUG_SBC_FRAME_TIMEOUT_RAW_DATA
    if(g_EVENT_REQ_SBC_FRAME_Timer == NULL) {
        uos_timer_create(&g_EVENT_REQ_SBC_FRAME_Timer);
        uos_timer_start(g_EVENT_REQ_SBC_FRAME_Timer, EVENT_REQ_SBC_FRAME_TIMEOUT / 5, 0, EVENT_REQ_SBC_FRAME_timeout, (uint32_t)param);
    }
#endif
}

void EVENT_REQ_SBC_FRAME_stop_timer()
{
#ifdef DEBUG_SBC_FRAME_TIMEOUT_RAW_DATA
    if(g_EVENT_REQ_SBC_FRAME_Timer != NULL) {
        uos_timer_stop(g_EVENT_REQ_SBC_FRAME_Timer);
        uos_timer_delete(g_EVENT_REQ_SBC_FRAME_Timer);
        g_EVENT_REQ_SBC_FRAME_Timer = NULL;
    }

#endif
}

void bbpro_pcm_tx_trigger(UINT32 arg)
{
    T_HCI_MSG msg;
    /*int used_size;*/

    // check used buf which can be send as one packet?
    if((/*used_size =*/ bbpro_rbuf_used(g_pcm_tx_rbuf)) >= HCI_AUDIO_DATA_WIDTH) {
        msg.type = HCI_MSG_TYPE_8763BF;
        msg.subtype = BBPRO_HCI_CMD_AUDIO_DATA;

        bbpro_hci_msg_queue_send(&msg);
    }
}

void bbpro_start_pcm_tx_timer(void)
{
    MODLOGD("%s, %x", __func__, g_bbpro_PCMTxTimer);
    if(g_bbpro_PCMTxTimer == NULL) {
        uos_timer_create(&g_bbpro_PCMTxTimer);
        uos_timer_start(g_bbpro_PCMTxTimer, MS_TO_TICKS(BBPRO_PCM_TX_TRIGGER_TIMEOUT), MS_TO_TICKS(BBPRO_PCM_TX_TRIGGER_TIMEOUT), bbpro_pcm_tx_trigger, (uint32_t)0);
    }
}

void bbpro_stop_pcm_tx_timer(void)
{
    MODLOGD("%s, %x", __func__, g_bbpro_PCMTxTimer);
    if(g_bbpro_PCMTxTimer != NULL) {
        uos_timer_stop(g_bbpro_PCMTxTimer);
        uos_timer_delete(g_bbpro_PCMTxTimer);
        g_bbpro_PCMTxTimer = NULL;
    }
}


bool bbpro_hci_send(T_HCI_MSG * hci_msg)
{
    uint32_t event[4];
    static uint32_t retry_count = 0;

    switch(hci_msg->subtype) {
        case BBPRO_HCI_SEND_WAKE_UP: {
            hci_cmd_send_wake_up();
            break;
        }
        case BBPRO_HCI_SEND_POWER_ON_PRESSED: {
            hci_app_send_power_on_button_press_cmd();
            break;
        }
        case BBPRO_HCI_SEND_POWER_ON_RELEASED: {
            APP_PRINT_INFO0("[talkband] BBPRO_HCI_SEND_POWER_ON_RELEASED!");
            hci_app_send_power_on_button_release_cmd();
            break;
        }
        case BBPRO_HCI_SEND_POWER_OFF_PRESSED: {
            hci_app_send_power_off_button_press_cmd();
            break;
        }
        case BBPRO_HCI_SEND_POWER_OFF_RELEASED: {
            APP_PRINT_INFO0("[talkband] BBPRO_HCI_SEND_POWER_OFF_RELEASED!");
            hci_app_send_power_off_button_release_cmd();
            break;
        }
        case BBPRO_HCI_SEND_SYSTEM_RESET: {
            APP_PRINT_INFO0("[talkband] BBPRO_HCI_SEND_SYSTEM_RESET!");
            hci_app_send_power_off_button_release_cmd();
            break;
        }
        case BBPRO_HCI_SEND_ADD_REMOVE_SCO: {
            hci_cmd_add_remove_sco();
            break;
        }
        case BBPRO_HCI_SEND_ENTER_PAIRING_MODE: {
            hci_cmd_enter_pairing_mode();
            break;
        }
        case BBPRO_HCI_SEND_EXIT_PAIRING_MODE: {
            hci_cmd_exit_pairing_mode();
            break;
        }
        case BBPRO_HCI_CREATE_CONNECTION: {
            uint8_t  remote_bd[6];
            memcpy(remote_bd, hci_msg->u.buf, hci_msg->len);
            MODLOGD("[talkband][BBPRO PEER ADDR] create connect by address %02x%02x%02x%02x%02x%02x",
                    remote_bd[0], remote_bd[1], remote_bd[2],
                    remote_bd[3], remote_bd[4], remote_bd[5]);
            hci_cmd_create_connection(CONNECT_WITH_BT_ADDR, (PROFILE_TYPE)(A2DP_PROFILE_MSAK | AVRCP_PROFILE_MSAK), remote_bd);
            break;
        }
        case BBPRO_HCI_GET_BT_ADDR: {
            hci_cmd_get_bt_addr();
            break;
        }
        case BBPRO_HCI_GET_BT_STATUS: {
            hci_cmd_get_status(LOCAL_APP_STATUS);
            break;
        }
        case BBPRO_HCI_RESET_TO_DEFAULT: {
            APP_PRINT_WARN0("[talkband] Prepare Factory Mode!");
            hci_cmd_reset_to_default();
            break;
        }
        case BBPRO_HCI_INITIATE_VOICE_DIAL: {
            hci_cmd_initiate_voice_dial();
            break;
        }
        case BBPRO_HCI_CANCEL_VOICE_DIAL: {
            hci_cmd_cancel_voice_dial();
            break;
        }
        case BBPRO_HCI_LINK_LAST_DEVICE: {
            APP_PRINT_INFO0("[talkband] BBPRO_HCI_LINK_LAST_DEVICE!");
            hci_cmd_link_last_device();
            break;
        }
        case BBPRO_HCI_DISCONNECT_ALL_LINK: {
            hci_cmd_disconnect_all_link();
            break;
        }
        case BBPRO_HCI_INCOMMING_CALL_ACCEPT: {
            APP_PRINT_WARN0("[talkband] Incoming Call Accept!");
            hci_cmd_answer();
        }
        break;
        case BBPRO_HCI_INCOMMING_CALL_REJECT: {
            APP_PRINT_WARN0("[talkband] Incoming Call Reject!");
            hci_cmd_reject_call();
        }
        break;
        case BBPRO_HCI_END_CALL: {
            APP_PRINT_WARN0("[talkband] End Call !");
            hci_cmd_end_call();
        }
        break;
        case BBPRO_HCI_PUSH_TONE: {
            hci_cmd_push_tone(hci_msg->index, hci_msg->flag);
        }
        break;
        case BBPRO_HCI_DIAL_WITH_NUMBER: {
            hci_cmd_hfp_dial_with_number(hci_msg->u.buf, hci_msg->len);
        }
        break;
        case BBPRO_HCI_READ_PAIRED_RECORD: {
            hci_cmd_read_paired_record();
        }
        break;
        case BBPRO_HCI_PLAY_MEDIA_BY_NAME: {
            hci_cmd_play_media_by_name(hci_msg->u.buf, hci_msg->len);
        }
        break;
        case BBPRO_HCI_GET_MEDIA_INFO: {
            hci_cmd_get_media_info();
        }
        break;
        case BBPRO_HCI_GET_PLAY_LIST: {
            hci_cmd_get_play_list(hci_msg->u.param);
        }
        break;
        case BBPRO_HCI_SET_PLAY_MODE: {
            hci_cmd_set_play_mode(hci_msg->u.param);
        }
        break;
        case BBPRO_HCI_AV_PLAY_PAUSE: {
            hci_cmd_av_play_pause();
        }
        break;
        case BBPRO_HCI_AV_STOP: {
            hci_cmd_av_stop();
        }
        break;
        case BBPRO_HCI_VOL_UP: {
            hci_cmd_vol_up();
        }
        break;
        case BBPRO_HCI_VOL_DOWN: {
            hci_cmd_vol_down();
        }
        break;
        case BBPRO_HCI_AV_FWD: {
            hci_cmd_av_fwd();
        }
        break;
        case BBPRO_HCI_AV_BWD: {
            hci_cmd_av_bwd();
        }
        break;
        case BBPRO_HCI_INQUIRY_START: {
            hci_cmd_inquiry_start(hci_msg->u.inquiry_param.filter, hci_msg->u.inquiry_param.rssi,
                                  hci_msg->u.inquiry_param.inquiry_time);
        }
        break;
        case BBPRO_HCI_INQUIRY_STOP: {
            hci_cmd_inquiry_stop();
        }
        break;
        case BBPRO_HCI_REQ_SBC_OPERATION_PLAY: {
            hci_cmd_req_sbc_operation(SBC_OPERATION_PLAY);

            EVENT_REQ_SBC_FRAME_start_timer(NULL);
        }
        break;
        case BBPRO_HCI_REQ_SBC_OPERATION_PAUSE: {
            hci_cmd_req_sbc_operation(SBC_OPERATION_PAUSE);

            EVENT_REQ_SBC_FRAME_stop_timer();
        }
        break;
        case BBPRO_HCI_REQ_SBC_OPERATION_STOP: {
            hci_cmd_req_sbc_operation(SBC_OPERATION_STOP);

            EVENT_REQ_SBC_FRAME_stop_timer();
        }
        break;

        case BBPRO_HCI_REQ_SBC_OPERATION_NEXT: {
            hci_cmd_req_sbc_operation(SBC_OPERATION_NEXT);
        }
        break;

        case BBPRO_HCI_REQ_SBC_OPERATION_PREV: {
            hci_cmd_req_sbc_operation(SBC_OPERATION_PREV);
        }
        break;

        case BBPRO_HCI_SEND_SBC_FRAME: {
            void * data = hci_msg->u.buf;
            uint8_t n_frames = hci_msg->flag;
            uint16_t n_bytes = hci_msg->len;

            if((bbpro_play_state == SBC_OPERATION_PAUSE) || (bbpro_play_state == SBC_OPERATION_STOP)) {
                EVENT_REQ_SBC_FRAME_stop_timer();

                ///MODLOGD("mem_d %08x", hci_msg->u.buf);
                retry_count = 0;
                WaitingHCIAckFlag = false;

                if(hci_msg->u.buf) {
                    free(hci_msg->u.buf);
                    hci_msg->u.buf = NULL;
                }

                return true;
            }

            hci_cmd_sbc_frame(data, n_frames, n_bytes);

            EVENT_REQ_SBC_FRAME_stop_timer();

            EVENT_REQ_SBC_FRAME_start_timer(hci_msg->u.buf);
        }
        break;

#ifdef DEBUG_SBC_FRAME_TIMEOUT_RAW_DATA
        case BBPRO_HCI_EVENT_REQ_SBC_FRAME_TIMEOUT: {
            uint32_t i;
            extern LoopQueue_TypeDef   LoopQueue;

            ///MODLOGD("mem_t %08x", hci_msg->u.buf);
            if(hci_msg->u.buf) {
                free(hci_msg->u.buf);
                hci_msg->u.buf = NULL;
            }

            MODLOGD("Dump LoopQueue buffer ri:%d wi:%d", LoopQueue.readIndex, LoopQueue.writeIndex);
            MODLOGD("================================");
            for(i = 0; i < LOOP_QUEUE_MAX_SIZE; i++) {
                if(i % 16 == 0)
                    fatal_printf("\n");

                fatal_printf("%02X", LoopQueue.buf[i]);
            }
            fatal_printf("\n");
            MODLOGD("================================");
        }
        retry_count = 0;
        WaitingHCIAckFlag = false;
        return true;
#endif
        case BBPRO_HCI_CMD_AUDIO_CONTROL: {
            MODLOGD("CMD_AUDIO_CONTROL");
            hci_trans_info.pcm_tx_seqn = 0;
            hci_cmd_audio_control();
        }
        break;
        case BBPRO_HCI_CMD_AUDIO_DATA: {
            uint8_t cmd_packet[6 + HCI_AUDIO_DATA_SEQN_WIDTH + HCI_AUDIO_DATA_WIDTH + 1];
            uint8_t * param;
            /*int ret = HCI_AUDIO_DATA_WIDTH;*/
            int used_size;

            ///MODLOGD("CMD_AUDIO_DATA");

            /*
             * in theory, bbpro_send_pcm_data() make sure the size is enougth,
             * actually, check used data for safety
             */
            if((used_size = bbpro_rbuf_used(g_pcm_tx_rbuf)) < HCI_AUDIO_DATA_WIDTH) {
                MODLOGE("tx empty %d,%d", used_size, HCI_AUDIO_DATA_WIDTH);
#if TX_RBUF_RWSYNC_ENABLE == 1

#endif
                break;
            }

            param = &cmd_packet[6];
            param[0] = hci_trans_info.pcm_tx_seqn & 0xFF;
            param[1] = (hci_trans_info.pcm_tx_seqn >> 8) & 0xFF;
            hci_trans_info.pcm_tx_seqn ++;
            /*ret =*/ bbpro_rbuf_read(g_pcm_tx_rbuf, &param[HCI_AUDIO_DATA_INDEX], HCI_AUDIO_DATA_WIDTH);

            ///MODLOGD("cmd pcm, %d, %d, %d", HCI_AUDIO_DATA_WIDTH, HCI_AUDIO_DATA_WIDTH, ret);

#if TX_RBUF_RWSYNC_ENABLE == 1
            /*
             * Do I need to check available free space and then SetFlag? No.
             * reason:
             * 1. SetFlag as quickly as possible
             * 2. if bbpro_rbuf_size(g_pcm_tx_rbuf) < PCM_TX_SEND_BYTE,
             *    then the available free space is always smaller than PCM_TX_SEND_BYTE
             */
            if(bTxWaitAvailable) {
                UOS_SetFlag(TxWaitAvailableFlag, RBUF_HAS_AVAILABLE_SIZE, OSA_FLAG_OR);
            }
#endif
            hci_cmd_audio_data(cmd_packet, sizeof(cmd_packet));

            // try more?
        }
        break;
        case BBPRO_HCI_CMD_I2S_STATUS: {
            MODLOGD("CMD_I2S_STATUS: %d", hci_msg->u.param);
            hci_cmd_send_i2s_status(hci_msg->u.param);
        }
        break;
        default:
            MODLOGE("[talkband]send error cmd fail!");
            break;
    }

    if(hci_msg->subtype == BBPRO_HCI_CMD_AUDIO_DATA) {
        WaitingHCIAckFlag = false;
        return true;
    }

    WaitingHCIAckFlag = true;

    if((uos_wait_msg((uint32_t *)event, bbppro_hci_ack_queue_handle, 100) == NULL) && (event[0] == 0x12345678)) {
        ///APP_PRINT_INFO0("[talkband]bbp hci receive ACK success!");
        retry_count = 0;
        WaitingHCIAckFlag = false;

        switch(hci_msg->subtype) {
            case BBPRO_HCI_SEND_SBC_FRAME: {
                ///MODLOGD("mem_f %08x", hci_msg->u.buf);
                if(hci_msg->u.buf) {
                    free(hci_msg->u.buf);
                    hci_msg->u.buf = NULL;
                }
            }
            break;
            default:
                break;
        }

        return true;
    } else {
        extern bt_uart_cfg rtlbt_uart_port;

        retry_count++;
        MODLOGD("do retry count = %d(%d)", retry_count, hci_msg->subtype);
        if(retry_count < BBPRO_MAX_RESEND_COUNT) {
            hci_trans_info.hci_tx_seqn--;
            bbpro_hci_send(hci_msg);
        }
        retry_count = 0;
        WaitingHCIAckFlag = false;

        switch(hci_msg->subtype) {
            case BBPRO_HCI_SEND_SBC_FRAME: {
                ///MODLOGD("mem_f1 %08x", hci_msg->u.buf);
                if(hci_msg->u.buf) {
                    free(hci_msg->u.buf);
                    hci_msg->u.buf = NULL;
                }
            }
            break;
            default:
                break;
        }

        return false;
    }
}

void bbpro_hci_msg_queue_send(T_HCI_MSG * p_msg)
{
    UI_EVENT ev = {0};
    T_HCI_MSG * hci_msg;
    BOOL status;
    extern bool hci_module_has_installed;

    if(hci_module_has_installed == false) {
        return;
    }

    memset((VOID *)&ev, 0x0, sizeof(UI_EVENT));
    hci_msg = (T_HCI_MSG *)malloc(sizeof(T_HCI_MSG));
    if(hci_msg == NULL) {
        MODLOGE("malloc hci_msg NULL");
        return;
    }
    memcpy(hci_msg, p_msg, sizeof(T_HCI_MSG));
    ev.nEventId = 0x1234;
    ev.nParam1 = (UINT32)hci_msg;
    if((status = uos_send_event(bbpro_hci_send_task_handle, &ev, UOS_WAIT_FOREVER, UOS_EVENT_PRI_NORMAL)) != true) {
        APP_PRINT_ERROR0("[talkband]bbpro hci send msgfail, status:%d, subtype:%d", status, p_msg->subtype);
    }
}

/**
 * @brief      bbp hci send task to handle events & messages
 * @param[in]  p_param  Parameters sending to the task
 * @return     void
 */
void bbpro_hci_send_task(void * p_param)
{
    UI_EVENT ev;
    T_HCI_MSG * hci_msg;

    uos_sleep(50);

    while(true) {
        memset(&ev, 0, sizeof(ev));
        if(uos_wait_event(bbpro_hci_send_task_handle, &ev, UOS_WAIT_FOREVER) == true) {
            hci_msg = (T_HCI_MSG *)ev.nParam1;
            if(hci_msg) {
                bbpro_hci_send(hci_msg);
                free(hci_msg);
            } else
                MODLOGE("send task wait hci_msg NULL");
        } else
            MODLOGE("send task wait hci_msg failed, nParam1:0x%x", ev.nParam1);
    }
}


void bbpro_hci_receive_task(void * p_param)
{
    UI_EVENT ev;

    uos_sleep(50);

    while(true) {
        memset(&ev, 0, sizeof(ev));
        if(uos_wait_event(bbpro_hci_receive_task_handle, &ev, UOS_WAIT_FOREVER) == true) {
#ifdef SEND_EVENT_TO_RECV_TASK_WITH_PARAM
            Rx_PackDebugTypeDef * event;
            event = (Rx_PackDebugTypeDef *)ev.nParam1;
            if(event == NULL) {
                MODLOGD("receive task receive event NULL");
                continue;
            }
#endif
            switch(ev.nEventId) {
                case IO_MSG_UART_RX_PKT: {
#ifdef SEND_EVENT_TO_RECV_TASK_WITH_PARAM
                    uint32_t i;
                    extern LoopQueue_TypeDef   LoopQueue;
                    extern unsigned char BTUARTDMARXbuffer0[2048];
                    extern unsigned char BTUARTDMARXbuffer1[2048];

                    if(event->packet_type == PACKET_TYPE_ENTIRED) {
                        MODLOGE("whole:%08X,%d,%08X,%d", event->param1, event->param2, event->param3, event->param4);
                    } else if(event->packet_type == PACKET_TYPE_ASSEMBLED) {
                        MODLOGE("asmb:%08X,%d,%08X,%d", event->param1, event->param2, event->param3, event->param4);
                        break;
                    } else if(event->packet_type == PACKET_TYPE_LAST) {
                        MODLOGE("last:%08X,%d,%08X,%d", event->param1, event->param2, event->param3, event->param4);
                    } else if((event->packet_type == PACKET_TYPE_BROKEN)) {
                        MODLOGE("broken:%08X,%d,%08X,%d", event->param1, event->param2, event->param3, event->param4);
                        MODLOGE("ri:%d wi:%d", LoopQueue.readIndex, LoopQueue.writeIndex);

                        MODLOGD("LoopQueue======================");
                        for(i = 0; i < LOOP_QUEUE_MAX_SIZE; i++) {
                            if(i % 16 == 0)
                                fatal_printf("\n");

                            fatal_printf("%02X", LoopQueue.buf[i]);
                        }
                        MODLOGD("================================");
                        fatal_printf("\n");

                        MODLOGD("DUMP DMA0: 0x%08x===================", BTUARTDMARXbuffer0);
                        for(i = 0; i < 2048; i++) {
                            if(i % 16 == 0)
                                fatal_printf("\n");

                            fatal_printf("%02X", BTUARTDMARXbuffer0[i]);
                        }
                        fatal_printf("\n");

                        MODLOGD("DUMP DMA1: 0x%08x===================", BTUARTDMARXbuffer1);
                        for(i = 0; i < 2048; i++) {
                            if(i % 16 == 0)
                                fatal_printf("\n");

                            fatal_printf("%02X", BTUARTDMARXbuffer1[i]);
                        }
                        fatal_printf("\n");

                        ASSERT(0);

                    }
#endif

                    uart_rx_lock();
                    if(DataTrans_HandleRX() == true) {
                        if(!uos_is_event_available(bbpro_hci_receive_task_handle)) {
                            if(!DataTrans_HandleRX()) {

                            }
                        }
                    } else {

                    }
                    uart_rx_unlock();

                    break;
                }
                default:
                    break;
            }
#ifdef SEND_EVENT_TO_RECV_TASK_WITH_PARAM
            free(event);
#endif
        } else
            MODLOGE("receive task wait failed");
    }
}

/**
 * @brief  Initialize data trans task
 * @return void
 */
///extern void *app_task_handle;   //!< APP Task handle
void bbpro_hci_task_init(void)
{
    MODLOGD("%s++", __func__);

    if(bbpro_hci_send_task_handle == NULL) {
        bbpro_hci_send_task_handle = uos_create_task(bbpro_hci_send_task,
                                     0,
                                     BBPRO_HCI_SEND_TASK_MSGQ_SIZE,
                                     BBPRO_HCI_SEND_TASK_STACK_SIZE,
                                     BBPRO_HCI_SEND_TASK_PRIORITY,
                                     "B3 S task");
        if(bbpro_hci_send_task_handle == NULL) {
            MODLOGE("create bbpro_hci_send_task_handle failed\n");
            ///ASSERT(0);
        }
    }

    if(bbpro_hci_receive_task_handle == NULL) {
        bbpro_hci_receive_task_handle = uos_create_task(bbpro_hci_receive_task,
                                        0,
                                        BBPRO_HCI_RECEIVE_TASK_MSGQ_SIZE,
                                        BBPRO_HCI_RECEIVE_TASK_STACK_SIZE,
                                        BBPRO_HCI_RECEIVE_TASK_PRIORITY,
                                        "B3 R task");
        if(bbpro_hci_receive_task_handle == NULL) {
            MODLOGE("create bbpro_hci_receive_task_handle failed\n");
            ///ASSERT(0);
        }
    }
    MODLOGD("%s, send task: 0x%x, recv task: 0x%x", __func__, bbpro_hci_send_task_handle, bbpro_hci_receive_task_handle);

    if(bbppro_hci_ack_queue_handle == INVALID_MSGQ_ID) {
        bbppro_hci_ack_queue_handle = uos_new_message_queue("hci_ack_queue", BBPRO_HCI_ACK_MSGQ_SIZE);
        if(bbppro_hci_ack_queue_handle == INVALID_MSGQ_ID) {
            MODLOGE("create bbppro_hci_ack_queue_handle failed\n");
            ///ASSERT(0);
        }
    }

    if(g_uart_rx_mutex_lock == INVALID_MUTEX_ID) {
        g_uart_rx_mutex_lock = uos_new_mutex();
        if(g_uart_rx_mutex_lock == INVALID_MUTEX_ID) {
            MODLOGE("create g_uart_rx_mutex_lock failed\n");
            ///ASSERT(0);
        }
    }

    if(sbcframe_request_flag == INVALID_FLAG_ID) {
        sbcframe_request_flag = uos_create_flag();
        if(sbcframe_request_flag == INVALID_FLAG_ID) {
            MODLOGE("create sbcframe_request_flag failed\n");
            ///ASSERT(0);
        }
    }

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
    g_pcm_tx_rbuf = bbpro_rbuf_create(1024 * 128);
#else
    g_pcm_tx_rbuf = bbpro_rbuf_create(0);
#endif
    if(g_pcm_tx_rbuf == NULL) {
        MODLOGE("create g_pcm_tx_rbuf failed\n");
        ///ASSERT(0);
    }
    bbpro_rbuf_set_mode(g_pcm_tx_rbuf, RBUF_MODE_BLOCKING);

#if TX_RBUF_RWSYNC_ENABLE == 1
    TxWaitAvailableFlag = uos_create_flag();
    if(TxWaitAvailableFlag == INVALID_FLAG_ID) {
        MODLOGE("create TxWaitAvailableFlag failed\n");
        ///ASSERT(0);
    }

    TxWaitUsedFlag = uos_create_flag();
    if(TxWaitUsedFlag == INVALID_FLAG_ID) {
        MODLOGE("create TxWaitUsedFlag failed\n");
        ///ASSERT(0);
    }
#endif

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
    g_pcm_rx_rbuf = bbpro_rbuf_create(1024 * 128);
#else
    g_pcm_rx_rbuf = bbpro_rbuf_create(0);
#endif
    if(g_pcm_rx_rbuf == NULL) {
        MODLOGE("create g_pcm_rx_rbuf failed\n");
        ///ASSERT(0);
    }
    bbpro_rbuf_set_mode(g_pcm_rx_rbuf, RBUF_MODE_BLOCKING);

#if RX_RBUF_RWSYNC_ENABLE == 1
    RxWaitAvailableFlag = uos_create_flag();
    if(RxWaitAvailableFlag == INVALID_FLAG_ID) {
        MODLOGE("create RxWaitAvailableFlag failed\n");
        ///ASSERT(0);
    }

    RxWaitUsedFlag = uos_create_flag();
    if(RxWaitUsedFlag == INVALID_FLAG_ID) {
        MODLOGE("create RxWaitUsedFlag failed\n");
        ///ASSERT(0);
    }
#endif

    MODLOGD("%s--", __func__);
}

void bbpro_hci_task_deinit(void)
{
    MODLOGD("%s++", __func__);

    if(bbpro_hci_send_task_handle) {
        uos_delete_task((TASK_HANDLE *)bbpro_hci_send_task_handle);
        bbpro_hci_send_task_handle = NULL;
    }

    if(bbpro_hci_receive_task_handle) {
        uos_delete_task((TASK_HANDLE *)bbpro_hci_receive_task_handle);
        bbpro_hci_receive_task_handle = NULL;
    }

    if(bbppro_hci_ack_queue_handle != INVALID_MSGQ_ID) {
        uos_free_msg(bbppro_hci_ack_queue_handle);
        bbppro_hci_ack_queue_handle = INVALID_MSGQ_ID;
    }

    if(g_uart_rx_mutex_lock != INVALID_MUTEX_ID) {
        uos_free_mutex(g_uart_rx_mutex_lock);
        g_uart_rx_mutex_lock = INVALID_MUTEX_ID;
    }

    if(sbcframe_request_flag != INVALID_FLAG_ID) {
        uos_delete_flag(sbcframe_request_flag);
        sbcframe_request_flag = INVALID_FLAG_ID;
    }

    if(g_pcm_tx_rbuf) {
        bbpro_rbuf_destroy(g_pcm_tx_rbuf);
        g_pcm_tx_rbuf = NULL;
    }
    if(g_pcm_rx_rbuf) {
        bbpro_rbuf_destroy(g_pcm_rx_rbuf);
        g_pcm_rx_rbuf = NULL;
    }

#if TX_RBUF_RWSYNC_ENABLE == 1
    if(TxWaitAvailableFlag) {
        uos_delete_flag(TxWaitAvailableFlag);
        TxWaitAvailableFlag = INVALID_FLAG_ID;
    }

    if(TxWaitUsedFlag) {
        uos_delete_flag(TxWaitUsedFlag);
        TxWaitUsedFlag = INVALID_FLAG_ID;
    }
#endif

#if RX_RBUF_RWSYNC_ENABLE == 1
    if(RxWaitAvailableFlag) {
        uos_delete_flag(RxWaitAvailableFlag);
        RxWaitAvailableFlag = INVALID_FLAG_ID;
    }

    if(RxWaitUsedFlag) {
        uos_delete_flag(RxWaitUsedFlag);
        RxWaitUsedFlag = INVALID_FLAG_ID;
    }
#endif

    MODLOGD("%s--", __func__);
}

#endif/*USE_LV_BLUETOOTH*/

/******************* (C) COPYRIGHT 2018 Realtek Semiconductor Corporation *****END OF FILE****/

